import { expect } from 'chai';
import parseDicom from '../src/parseDicom';

describe('parseDicom', () => {

  function convertToByteArray(jsArray) {
    const byteArray = new Uint8Array(jsArray.length);
    let index = 0;
    
    for (let i = 0; i < jsArray.length; i++) {
        byteArray[index++] = jsArray[i];
    }

    return byteArray;
  }
  
  function makeBigEndianTestData() {
    const rawData = [
      // Preamble
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      // Prefix
      0x44,0x49,0x43,0x4D,
      // File Meta Information Group Length
      // x00020000          UL         4
      0x02,0x00,0x00,0x00, 0x55,0x4C, 0x04,0x00, 0x9F,0x00,0x00,0x00,
      // File Meta Information Version
      // x00020001          OB        (reserved)   2                   01
      0x02,0x00,0x01,0x00, 0x4F,0x42, 0x00,0x00, 0x02,0x00,0x00,0x00, 0x00,0x01,
      // Media Storage SOP Class UID
      // x00020002          UI         26         1.2.840.10008.5.1.4.1.1.2 (CT)
      0x02,0x00,0x02,0x00, 0x55,0x49, 0x1A,0x00, 0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x30,0x30,0x30,0x38,0x2E,0x35,0x2E,0x31,0x2E,0x34,0x2E,0x31,0x2E,0x31,0x2E,0x32,0x00,
      // Media Storage SOP Instance UID
      // x00020003          UI         40         1.2.840.113704.1.111.3512.1336285465.198
      0x02,0x00,0x03,0x00, 0x55,0x49, 0x28,0x00, 0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x31,0x33,0x37,0x30,0x34,0x2E,0x31,0x2E,0x31,0x31,0x31,0x2E,0x33,0x35,0x31,0x32,0x2E,0x31,0x33,0x33,0x36,0x32,0x38,0x35,0x34,0x36,0x35,0x2E,0x31,0x39,0x38,
      // Transfer Syntax UID
      // x00020010          UI         20         1.2.840.10008.1.2.2 (Explicit VR Big Endian)
      0x02,0x00,0x10,0x00, 0x55,0x49, 0x14,0x00, 0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x30,0x30,0x30,0x38,0x2E,0x31,0x2E,0x32,0x2E,0x32,0x00,
      // Implementation Class UID
      // x00020012          UI         28         1.2.276.0.7230010.3.0.3.6.0
      0x02,0x00,0x12,0x00, 0x55,0x49, 0x1C,0x00, 0x31,0x2E,0x32,0x2E,0x32,0x37,0x36,0x2E,0x30,0x2E,0x37,0x32,0x33,0x30,0x30,0x31,0x30,0x2E,0x33,0x2E,0x30,0x2E,0x33,0x2E,0x36,0x2E,0x30,0x00,
      // Slice Location
      // x00201041          DS               4      '-43'
      0x00,0x20,0x10,0x41, 0x44,0x53, 0x00,0x04, 0x2D,0x34,0x33,0x00,
      // Rows
      // x00280010          US         2          512
      0x00,0x28,0x00,0x10, 0x55,0x53, 0x00,0x02, 0x02,0x00
    ];

    return convertToByteArray(rawData);
  }
  
  function makeExplicitLittleEndianTestData() {
    const rawData = [
      // Preamble
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      // Prefix
      0x44,0x49,0x43,0x4D,
      // File Meta Information Group Length
      // x00020000          UL         4
      0x02,0x00,0x00,0x00, 0x55,0x4C, 0x04,0x00, 0x9F,0x00,0x00,0x00,
      // File Meta Information Version
      // x00020001          OB        (reserved)  2                     01
      0x02,0x00,0x01,0x00, 0x4F,0x42, 0x00,0x00, 0x02,0x00,0x00,0x00, 0x00,0x01,
      // Media Storage SOP Class UID
      // x00020002          UI         26         1.2.840.10008.5.1.4.1.1.2 (CT)
      0x02,0x00,0x02,0x00, 0x55,0x49, 0x1A,0x00, 0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x30,0x30,0x30,0x38,0x2E,0x35,0x2E,0x31,0x2E,0x34,0x2E,0x31,0x2E,0x31,0x2E,0x32,0x00,
      // Media Storage SOP Instance UID
      // x00020003          UI         40         1.2.840.113704.1.111.3512.1336285465.198
      0x02,0x00,0x03,0x00, 0x55,0x49, 0x28,0x00, 0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x31,0x33,0x37,0x30,0x34,0x2E,0x31,0x2E,0x31,0x31,0x31,0x2E,0x33,0x35,0x31,0x32,0x2E,0x31,0x33,0x33,0x36,0x32,0x38,0x35,0x34,0x36,0x35,0x2E,0x31,0x39,0x38,
      // Transfer Syntax UID
      // x00020010          UI         20         1.2.840.10008.1.2.1 (Explicit VR Little Endian)
      0x02,0x00,0x10,0x00, 0x55,0x49, 0x14,0x00, 0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x30,0x30,0x30,0x38,0x2E,0x31,0x2E,0x32,0x2E,0x31,0x00,
      // Implementation Class UID
      // x00020012          UI         28         1.2.276.0.7230010.3.0.3.6.0
      0x02,0x00,0x12,0x00, 0x55,0x49, 0x1C,0x00, 0x31,0x2E,0x32,0x2E,0x32,0x37,0x36,0x2E,0x30,0x2E,0x37,0x32,0x33,0x30,0x30,0x31,0x30,0x2E,0x33,0x2E,0x30,0x2E,0x33,0x2E,0x36,0x2E,0x30,0x00,
      // Slice Location
      // x00201041          DS               4      '-43'
      0x20,0x00,0x41,0x10, 0x44,0x53, 0x04,0x00, 0x2D,0x34,0x33,0x00,
      // Rows
      // x00280010          US         2          512
      0x28,0x00,0x10,0x00, 0x55,0x53, 0x02,0x00, 0x00,0x02
    ];

    return convertToByteArray(rawData);
  }
  
  function makeImplicitLittleEndianTestData() {
    const rawData = [
      // Preamble
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      // Prefix
      0x44,0x49,0x43,0x4D,
      // File Meta Information Group Length
      // x00020000          UL         4
      0x02,0x00,0x00,0x00, 0x55,0x4C, 0x04,0x00, 0x9D,0x00,0x00,0x00,
      // File Meta Information Version
      // x00020001          OB        (reserved)   2                    01
      0x02,0x00,0x01,0x00, 0x4F,0x42, 0x00,0x00, 0x02,0x00,0x00,0x00, 0x00,0x01,
      // Media Storage SOP Class UID
      // x00020002          UI         26         1.2.840.10008.5.1.4.1.1.2 (CT)
      0x02,0x00,0x02,0x00, 0x55,0x49, 0x1A,0x00, 0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x30,0x30,0x30,0x38,0x2E,0x35,0x2E,0x31,0x2E,0x34,0x2E,0x31,0x2E,0x31,0x2E,0x32,0x00,
      // Media Storage SOP Instance UID
      // x00020003          UI         40         1.2.840.113704.1.111.3512.1336285465.198
      0x02,0x00,0x03,0x00, 0x55,0x49, 0x28,0x00, 0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x31,0x33,0x37,0x30,0x34,0x2E,0x31,0x2E,0x31,0x31,0x31,0x2E,0x33,0x35,0x31,0x32,0x2E,0x31,0x33,0x33,0x36,0x32,0x38,0x35,0x34,0x36,0x35,0x2E,0x31,0x39,0x38,
      // Transfer Syntax UID
      // x00020010          UI         20         1.2.840.10008.1.2 (Implicit VR Little Endian)
      0x02,0x00,0x10,0x00, 0x55,0x49, 0x12,0x00, 0x31,0x2E,0x32,0x2E,0x38,0x34,0x30,0x2E,0x31,0x30,0x30,0x30,0x38,0x2E,0x31,0x2E,0x32,0x00,
      // Implementation Class UID
      // x00020012          UI         28         1.2.276.0.7230010.3.0.3.6.0
      0x02,0x00,0x12,0x00, 0x55,0x49, 0x1C,0x00, 0x31,0x2E,0x32,0x2E,0x32,0x37,0x36,0x2E,0x30,0x2E,0x37,0x32,0x33,0x30,0x30,0x31,0x30,0x2E,0x33,0x2E,0x30,0x2E,0x33,0x2E,0x36,0x2E,0x30,0x00,
      // Slice Location
      // x00201041                          4      '-43'
      0x20,0x00,0x41,0x10, 0x04,0x00, 0x00,0x00, 0x2D,0x34,0x33,0x00,
      // Rows
      // x00280010                      2          512
      0x28,0x00,0x10,0x00, 0x02,0x00, 0x00,0x00, 0x00,0x02
    ];

    return convertToByteArray(rawData);
  }
  
  function assertMetaHeaderElements(dataSet, transferSyntax, groupLength) {
    expect(dataSet.uint32('x00020000')).to.equal(groupLength); // '(0002,0000) was not read correctly');
    expect(dataSet.uint16('x00020001')).to.equal(256); //'(0002,0001) was not read correctly');
    expect(dataSet.string('x00020002')).to.equal('1.2.840.10008.5.1.4.1.1.2'); //'(0002,0002) was not read correctly');
    expect(dataSet.string('x00020003')).to.equal('1.2.840.113704.1.111.3512.1336285465.198'); //'(0002,0003) was not read correctly');
    expect(dataSet.string('x00020010')).to.equal(transferSyntax); //'(0002,0010) was not read correctly');
    expect(dataSet.string('x00020012')).to.equal('1.2.276.0.7230010.3.0.3.6.0'); //'(0002,0012) was not read correctly');
  }

  it('should parse the dataset correctly (bigEndian)', () => {
    // Arrange
    const byteArray = makeBigEndianTestData();

    // Act
    const dataSet = parseDicom(byteArray);

    // Assert
    assertMetaHeaderElements(dataSet, '1.2.840.10008.1.2.2', 159);
    expect(dataSet.uint16('x00280010')).to.equal(512);
    expect(dataSet.string('x00201041')).to.equal('-43');
  });
    
  it('should parse the dataset correctly (explicitLittleEndian)', () => {
    // Arrange
    const byteArray = makeExplicitLittleEndianTestData();

    // Act
    const dataSet = parseDicom(byteArray);

    // Assert
    assertMetaHeaderElements(dataSet, '1.2.840.10008.1.2.1', 159);
    expect(dataSet.uint16('x00280010')).to.equal(512);
    expect(dataSet.string('x00201041')).to.equal('-43');
  });
    
  it('should parse the dataset correctly (implicitLittleEndian)', () => {
    // Arrange
    const byteArray = makeImplicitLittleEndianTestData();

    // Act
    const dataSet = parseDicom(byteArray);

    // Assert
    assertMetaHeaderElements(dataSet, '1.2.840.10008.1.2', 157);
    expect(dataSet.uint16('x00280010')).to.equal(512);
    expect(dataSet.string('x00201041')).to.equal('-43');
  });

});
